package com.liz.lizrpccore.beans.proxys.netty;

import com.alibaba.fastjson.JSON;
import com.liz.lizrpcapi.commons.Node;
import com.liz.lizrpccore.beans.proxys.base.BaseProxy;
import com.liz.lizrpccore.beans.proxys.netty.msgs.InvokerMessage;
import com.liz.lizrpccore.entity.LizRpcArg;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.serialization.ObjectDecoder;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author liangGongWei
 * @description
 * @create 2021-09-22 13:57
 **/

public class NettyBase extends BaseProxy {
    protected Object getResultFromRemoteNode(Class interfaceType, Method method, Object[] args, Node node) {
        String ip = node.getIp();
        String protocolPort = node.getProtocolPort();
        List<LizRpcArg> lizRpcArgs = super.generateArgList(args);

        InvokerMessage message = new InvokerMessage();
        message.setClassName(interfaceType.getName());
        message.setMethodName(method.getName());
        message.setLizRpcArgs(lizRpcArgs);
        List<Object> params = getArgs(lizRpcArgs);
        message.setParameterTypes(getParamsType(params.toArray()));

        final RpcProxyHandler customerHandler = new RpcProxyHandler();
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group);
            bootstrap.channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(Channel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                            pipeline.addLast("encoder", new ObjectEncoder());
                            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                            pipeline.addLast("myHandler", customerHandler);
                        }
                    });
            ChannelFuture future = bootstrap.connect(ip, Integer.parseInt(protocolPort)).sync();
            future.channel().writeAndFlush(message).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            group.shutdownGracefully();
        }
        return customerHandler.getResponse();
    }

    private Class<? extends Object>[] getParamsType(Object[] params){
        Class<? extends Object>[] paramClass = null;
        if (params != null) {
            int paramsLength = params.length;
            paramClass = new Class[paramsLength];
            for (int i = 0; i < paramsLength; i++) {
                paramClass[i] = params[i].getClass();
            }
        }
        return paramClass;
    }

    private List<Object> getArgs(List<LizRpcArg> argsList) {
        try {
            List<Object> res = new ArrayList<>();
            for (LizRpcArg arg : argsList) {
                Class<?> clazz = Class.forName(arg.getClassName());
                Object o = JSON.parseObject(arg.getObjStr(), clazz);
                res.add(o);
            }
            return res;
        } catch (Exception e) {
            throw new RuntimeException("参数转化异常：" + argsList);
        }
    }


}
